package com.bytecub.protocol.plugin.demo;

import com.alibaba.fastjson.JSONObject;
import com.bytecub.common.annotations.BcProtocolAnnotation;
import com.bytecub.common.biz.TopicBiz;
import com.bytecub.common.constants.BCConstants;
import com.bytecub.common.domain.message.DeviceDownMessage;
import com.bytecub.common.domain.message.DeviceReportMessage;
import com.bytecub.common.domain.message.UpgradeReplyMessage;
import com.bytecub.common.domain.message.gateway.SubDeviceMessage;
import com.bytecub.common.enums.BCErrorEnum;
import com.bytecub.common.enums.DeviceReplyEnum;
import com.bytecub.common.exception.BCGException;
import com.bytecub.common.metadata.ProductFuncTypeEnum;
import com.bytecub.mdm.service.IDeviceService;
import com.bytecub.protocol.base.IBaseProtocol;
import com.bytecub.protocol.domain.demo.ReplyResultBo;
import com.bytecub.utils.JSONProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

/**
 * * ByteCub.cn. * Copyright (c) 2020-2020 All Rights Reserved. * * @author bytecub@163.com songbin
 * * @version Id: DemoProtocolService.java, v 0.1 2020-12-07 Exp $$
 */
@Slf4j
@Data
@BcProtocolAnnotation(name = "演示协议", protocolCode = "demo", desc = "演示协议")
@Component
public class DemoProtocolService implements IBaseProtocol {
    private static final String CHARSET = BCConstants.GLOBAL.CHARSET_GB2312;
    @Autowired IDeviceService deviceService;

    @Override
    public DeviceReportMessage decode(String topic, String deviceCode, byte[] payload) {
        try {
            DeviceReportMessage deviceMessage = new DeviceReportMessage<>();
            String topicDeviceCode = TopicBiz.parseDeviceCode(topic);
            if (!deviceCode.equals(topicDeviceCode)) {
                log.warn("设备[{}]上报topic[{}]权限不足", deviceCode, topic);
                String extraMsg = String.format("设备[%s]上报topic[%s]权限不足", deviceCode, topic);
                throw BCGException.genException(BCErrorEnum.ES_CREATE_EXCEPTION, extraMsg);
            }

            String msg = new String(payload, CHARSET);
            // log.info("[{}]准备解析协议【{}】:{}", topic, payload);
            /** 属性上报 */
            this.parsePropMessage(topic, payload, deviceMessage);
            /** 事件上报 */
            this.parseEventMessage(topic, payload, deviceMessage);
            /** 消息回执上报 */
            this.parseReplyMessage(topic, payload, deviceMessage);
            /** 设备属性读取回执 */
            this.parsePropertyGetMessage(topic, payload, deviceMessage);
            this.parseSubOffline(topic, payload, deviceMessage);
            this.parseSubOnline(topic, payload, deviceMessage);
            this.parseUpgradeReplyMessage(topic, payload, deviceMessage);
            this.subDeviceUpMsgProcess(topic, payload, deviceMessage);
            return deviceMessage;
        } catch (Exception e) {
            log.warn("解析协议异常:{}", payload, e);
        }
        return null;
    }

    @Override
    public byte[] encode(String topic, String deviceCode, DeviceDownMessage deviceDownMessages) {
        try {
            String msg = JSONProvider.toJSONString(deviceDownMessages);
            return msg.getBytes(CHARSET);
        } catch (Exception e) {
            log.warn("加密数据异常 topic:{} device:{} body:{}", topic, deviceCode, deviceDownMessages);
            return null;
        }
    }

    @Override
    public byte[] encodeBatch(String deviceCode, List<DeviceDownMessage> deviceDownMessages) {
        try {
            String msg = JSONProvider.toJSONString(deviceDownMessages);
            return msg.getBytes(CHARSET);
        } catch (Exception e) {
            log.warn("加密数据异常  device:{} body:{}", deviceCode, deviceDownMessages);
            return null;
        }
    }

    private void parsePropMessage(String topic, byte[] payload, DeviceReportMessage deviceMessage) {
        try {
            ProductFuncTypeEnum funcTypeEnum = TopicBiz.parseFuncTypeEnum(topic);
            if (!topic.endsWith("prop")) {
                return;
            }
            String msg = new String(payload, CHARSET);
            Map<String, Object> map = JSONProvider.parseObjectDefValue(msg, Map.class);
            deviceMessage.setValue(map);
        } catch (Exception e) {
            log.warn("解析协议异常", e);
            String extraMsg = "解析主题:" + topic + " 的上报消息异常";
            throw BCGException.genException(BCErrorEnum.PARSE_MSG_EXCEPTION, extraMsg);
        }
    }

    private void parseEventMessage(
            String topic, byte[] payload, DeviceReportMessage deviceMessage) {
        try {
            ProductFuncTypeEnum funcTypeEnum = TopicBiz.parseFuncTypeEnum(topic);
            if (!topic.endsWith("event")) {
                return;
            }
            String msg = new String(payload, CHARSET);
            Map<String, Object> map = JSONProvider.parseObjectDefValue(msg, Map.class);
            deviceMessage.setValue(map);
        } catch (Exception e) {
            log.warn("解析协议异常", e);
            String extraMsg = "解析主题:" + topic + " 的上报消息异常";
            throw BCGException.genException(BCErrorEnum.PARSE_MSG_EXCEPTION, extraMsg);
        }
    }

    private void parseReplyMessage(
            String topic, byte[] payload, DeviceReportMessage deviceMessage) {
        try {
            ProductFuncTypeEnum funcTypeEnum = TopicBiz.parseFuncTypeEnum(topic);
            if (!topic.endsWith(BCConstants.TOPIC.MSG_REPLY)) {
                return;
            }
            String msg = new String(payload, CHARSET);
            deviceMessage.setReplyMessage(msg);
            Map<String, Object> map = JSONProvider.parseObjectDefValue(msg, Map.class);
            deviceMessage.setMessageId((String) map.get("messageId"));
            ReplyResultBo replyResultBo =
                    JSONProvider.parseJsonObject(
                            (JSONObject) map.get("result"), ReplyResultBo.class);
            if (200 == replyResultBo.getCode()) {
                deviceMessage.setStatus(DeviceReplyEnum.SUCCESS);
            } else if (-1 == replyResultBo.getCode()) {
                deviceMessage.setStatus(DeviceReplyEnum.UNKNOWN);
            } else {
                deviceMessage.setStatus(DeviceReplyEnum.FAIL);
            }
        } catch (Exception e) {
            log.warn("解析协议异常", e);
            String extraMsg = "解析主题:" + topic + " 的回执消息异常";
            throw BCGException.genException(BCErrorEnum.PARSE_MSG_EXCEPTION, extraMsg);
        }
    }

    /** 读取设备属性回执上报 */
    private void parsePropertyGetMessage(
            String topic, byte[] payload, DeviceReportMessage deviceMessage) {
        try {
            if (!topic.endsWith(BCConstants.TOPIC.PROP_GET_REPLY)) {
                return;
            }
            String msg = new String(payload, CHARSET);
            Map<String, Object> map = JSONProvider.parseObjectDefValue(msg, Map.class);
            deviceMessage.setMessageId((String) map.get("messageId"));
            deviceMessage.setValue((Map) map.get("value"));
        } catch (Exception e) {
            log.warn("解析协议异常", e);
            String extraMsg = "解析主题:" + topic + " 的回执消息异常";
            throw BCGException.genException(BCErrorEnum.PARSE_MSG_EXCEPTION, extraMsg);
        }
    }

    /** 设备升级指令上报 */
    private void parseUpgradeReplyMessage(
            String topic, byte[] payload, DeviceReportMessage deviceMessage) {
        try {
            if (!topic.endsWith(BCConstants.TOPIC.UPGRADE_REPLY)) {
                return;
            }
            String msg = new String(payload, CHARSET);
            deviceMessage.setReplyMessage(msg);
            Map<String, Object> map = JSONProvider.parseObjectDefValue(msg, Map.class);
            deviceMessage.setMessageId((String) map.get("messageId"));
            UpgradeReplyMessage replyResultBo =
                    JSONProvider.parseJsonObject(
                            (JSONObject) map.get("result"), UpgradeReplyMessage.class);
            replyResultBo.setMessageId((String) map.get("messageId"));
        } catch (Exception e) {
            log.warn("解析协议异常", e);
            String extraMsg = "解析主题:" + topic + " 的回执消息异常";
            throw BCGException.genException(BCErrorEnum.PARSE_MSG_EXCEPTION, extraMsg);
        }
    }

    /** 网关子设备上线 */
    private void parseSubOnline(String topic, byte[] payload, DeviceReportMessage deviceMessage) {
        try {
            if (!topic.endsWith("online")) {
                return;
            }
            String msg = new String(payload, CHARSET);
            List<String> devices = JSONProvider.parseArrayObject(msg, String.class);
            deviceMessage.setDevices(devices);
        } catch (Exception e) {
            log.warn("解析协议异常", e);
            String extraMsg = "解析主题:" + topic + " 子设备上线解析异常";
            throw BCGException.genException(BCErrorEnum.PARSE_MSG_EXCEPTION, extraMsg);
        }
    }

    private void parseSubOffline(String topic, byte[] payload, DeviceReportMessage deviceMessage) {
        try {
            if (!topic.endsWith("online")) {
                return;
            }
            String msg = new String(payload, CHARSET);
            List<String> devices = JSONProvider.parseArrayObject(msg, String.class);
            deviceMessage.setDevices(devices);
        } catch (Exception e) {
            log.warn("解析协议异常", e);
            String extraMsg = "解析主题:" + topic + " 子设备下线解析异常";
            throw BCGException.genException(BCErrorEnum.PARSE_MSG_EXCEPTION, extraMsg);
        }
    }

    /** 处理来自网关设备上报的子设备消息 */
    private void subDeviceUpMsgProcess(
            String topic, byte[] payload, DeviceReportMessage deviceMessage) {
        try {
            if (!topic.endsWith("sub")) {
                return;
            }
            String msg = new String(payload, CHARSET);
            SubDeviceDataBody subDeviceDataBody =
                    JSONProvider.parseObjectDefValue(msg, SubDeviceDataBody.class);
            List<SubDeviceData> messages = subDeviceDataBody.getMessages();
            if (CollectionUtils.isEmpty(messages)) {
                // 解析出来没有任何值，直接返回
                return;
            }
            List<SubDeviceMessage> subDeviceMessages = new ArrayList<>();
            for (SubDeviceData item : messages) {
                try {
                    SubDeviceMessage subDeviceMessage = new SubDeviceMessage();
                    subDeviceMessage.setMessage(item.getMessage().getBytes(CHARSET));
                    subDeviceMessage.setDeviceCode(item.deviceCode);
                    subDeviceMessages.add(subDeviceMessage);
                } catch (Exception e) {
                    log.warn("转化子设备上报消息异常:{}", item, e);
                }
            }

            deviceMessage.setSubDeviceMsgList(subDeviceMessages);
        } catch (Exception e) {
            log.warn("解析协议异常", e);
            String extraMsg = "解析主题:" + topic + " 子设备消息解析异常";
            throw BCGException.genException(BCErrorEnum.PARSE_MSG_EXCEPTION, extraMsg);
        }
    }

    /** 内部用于接收网关子设备消息 */
    public static class SubDeviceData {
        private String deviceCode;
        private String message;

        public String getDeviceCode() {
            return deviceCode;
        }

        public void setDeviceCode(String deviceCode) {
            this.deviceCode = deviceCode;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }
    }

    /** 内部用于接收网关子设备消息 */
    public static class SubDeviceDataBody {
        /** 网关设备的编码 */
        private String deviceCode;

        private List<SubDeviceData> messages;

        public String getDeviceCode() {
            return deviceCode;
        }

        public void setDeviceCode(String deviceCode) {
            this.deviceCode = deviceCode;
        }

        public List<SubDeviceData> getMessages() {
            return messages;
        }

        public void setMessages(List<SubDeviceData> messages) {
            this.messages = messages;
        }
    }
}
